package com.study.jsl.wx;

import cn.hutool.bloomfilter.BitMapBloomFilter;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.study.jsl.wx.GzhDemo.DataDTO.ArticleDTO;
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.assertj.core.util.Lists;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.junit.jupiter.api.Test;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
import reactor.netty.tcp.TcpClient;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author zhuzi
 * 2025/1/2 8:14
 * 公众号
 */
@Slf4j
public class GzhDemo {
    static class TenTool {
        public static BitMapBloomFilter bloomFilter = new BitMapBloomFilter(10);
        public static WebClient webClient = null;

        static {
            ConnectionProvider provider = ConnectionProvider.builder("fixed").maxConnections(200) // 最大连接数
                    .maxIdleTime(Duration.ofSeconds(60)) // 最大空闲时间
                    .maxLifeTime(Duration.ofSeconds(60)) // 最大存活时间
                    .pendingAcquireTimeout(Duration.ofSeconds(60)) // 等待获取时间
                    .pendingAcquireMaxCount(1000) // 挂起的获取最大计数
                    .build();

            TcpClient tcpClient = TcpClient.create(provider)//
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 15000) // 连接超时时间
                    .doOnConnected(connection -> {
                        connection.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS)); // 读取超时
                        connection.addHandlerLast(new WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS)); // 写入超时
                    });

            HttpClient httpClient = HttpClient.from(tcpClient).keepAlive(true) // 启用保持连接
                    .responseTimeout(Duration.ofSeconds(10)); // 响应超时时间
            webClient = WebClient.builder()
                    //修改maxInMemorySize的缓存值，默认是256k。修改为10MB
                    .codecs(item -> item.defaultCodecs().maxInMemorySize(10 * 1024 * 1024)).clientConnector(new ReactorClientHttpConnector(httpClient)).build();
        }
    }

    public interface DataDTO {
        @Data
        @Accessors(chain = true)
        class ArticleDTO {
            private String title;
            private LocalDateTime pubTime;
            private String content;


        }
    }

    @Test
    public void gzh() {

        ArrayList<String> list = Lists.newArrayList("");
        List<ArticleDTO> collect = list.stream().map(ia -> article(ia)).sorted((s1, s2) -> new CompareToBuilder().append(s1.getPubTime(), s1.getPubTime()).toComparison()).collect(Collectors.toList());

        String jsonString = JSON.toJSONString(collect);
        FileUtil.writeUtf8String(jsonString, "/Users/zhuzi/Downloads/sql/安全饕/公众号.txt");
    }

    public static ArticleDTO article(String url) {

        String block = TenTool.webClient.get().uri(url).retrieve().bodyToMono(String.class).timeout(Duration.ofSeconds(8)).retry(3).block();
        block = StrUtil.replace(block, "section", "p");
        Document root = Jsoup.parse(block);
        Element titleEle = root.getElementById("activity-name");
        LocalDateTime localDateTime = null;
        try {
            String s = StrUtil.subBetween(block, "createTimestamp", ";");
            String s1 = StringUtils.replaceEach(s.trim(), new String[]{"=", " ", "'"}, new String[]{"", "", ""});
            localDateTime = LocalDateTimeUtil.of(1000 * Long.parseLong(s1));
        } catch (NumberFormatException e) {
            log.info("获取不到时间[{}-{}]", url, titleEle);
        }

        String s2 = html2Md(block);

        return new ArticleDTO().setContent(s2).setTitle(titleEle.text()).setPubTime(localDateTime);
    }

    @Test
    public void single() {
        String url = "https://mp.weixin.qq.com/s/COF6IBbmehBVlJ2I8FRVSQ";

        String block = TenTool.webClient.get().uri(url).retrieve().bodyToMono(String.class).timeout(Duration.ofSeconds(8)).retry(3).block();

        block = StrUtil.replace(block, "section", "p");
        String s2 = html2Md(block);
        FileUtil.writeUtf8String(s2, "/Users/zhuzi/Downloads/0051.md");
        Document root = Jsoup.parse(block);

        Element publishTime = root.getElementById("publish_time");

        System.out.println(publishTime.text());
        LocalDateTime parse = LocalDateTimeUtil.parse(publishTime.text(), "yyyy年MM月dd日 HH:mm");


        Element titleEle = root.getElementById("activity-name");
        System.out.println(titleEle);
        System.out.println(parse);
        String s = StrUtil.subBetween(block, "createTimestamp", ";");
        System.out.println(s);
        String s1 = StringUtils.replaceEach(s.trim(), new String[]{"=", " ", "'"}, new String[]{"", "", ""});
        LocalDateTime localDateTime = LocalDateTimeUtil.of(1000 * Long.parseLong(s1));
        System.out.println(localDateTime);


    }

    public static String html2Md(String html) {
        FlexmarkHtmlConverter converter = FlexmarkHtmlConverter.builder().build();
        String convert = converter.convert(html);
        List<String> split = StrUtil.split(convert, "\n");

        String collect = split.stream().map(item -> {
            if (!StrUtil.startWith(item, ">") && StringUtils.isNotBlank(item)) {
                item = "\n" + item;
            }
            return item;
        }).collect(Collectors.joining("\n"));
        return collect;
    }
}
